/**
 * 
 */
package org.vsg.common.ibatis3.support;

import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.support.DaoSupport;
import org.springframework.jdbc.JdbcUpdateAffectedIncorrectNumberOfRowsException;
import org.springframework.orm.ibatis.SqlMapClientOperations;
import org.springframework.util.Assert;

/**
 * @author Bill vison
 *
 */
public abstract class IBatis3DaoSupport extends DaoSupport {

	private SqlSessionFactory sqlSessionFactory
	;   
    private SqlSessionTemplate sqlSessionTemplate; 
	
	/* (non-Javadoc)
	 * @see org.springframework.dao.support.DaoSupport#checkDaoConfig()
	 */
	@Override
	protected void checkDaoConfig() throws IllegalArgumentException {
		// TODO Auto-generated method stub
		 Assert.notNull("sqlSessionFactory must be not null");
	}


	public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {   
        this.sqlSessionFactory = sqlSessionFactory;   
        this.sqlSessionTemplate = new SqlSessionTemplate(sqlSessionFactory);   
    }   
       
    public SqlSessionTemplate getSqlSessionTemplate() {   
        return sqlSessionTemplate;   
    } 	
	
	public static class SqlSessionTemplate {   
        SqlSessionFactory sqlSessionFactory;   

    	public SqlSessionFactory getSqlSessionFactory() {   
            return sqlSessionFactory;   
        }	
        
        public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {   
            this.sqlSessionFactory = sqlSessionFactory;   
        }   

        
        
        
		public Object insert(final String statementName, final Object parameterObject)
				throws DataAccessException {
			// TODO Auto-generated method stub
            return (Integer)execute(new SqlSessionCallback() {   
                public Object doInSession(SqlSession session) {   
                    return session.insert(statementName, parameterObject);   
                }   
            }); 
		}

		public Object execute(SqlSessionCallback action)  {   
            SqlSession session = null;   
            try {   
                session = sqlSessionFactory.openSession();   
                Object result = action.doInSession(session);   
                return result;   
            }finally {   
                if(session != null) {   
                    try {   
                        session.getConnection().close();   
                        session.close();   
                    } catch (SQLException e) {   
                        e.printStackTrace();   
                    }   
                }   
            }   
        }   

        
        
        
		public void delete(String statementName, Object parameterObject,
				int requiredRowsAffected) throws DataAccessException {
			// TODO Auto-generated method stub
			int actualRowsAffected = delete(statementName, parameterObject);
			if (actualRowsAffected != requiredRowsAffected) {
				throw new JdbcUpdateAffectedIncorrectNumberOfRowsException(
						statementName, requiredRowsAffected, actualRowsAffected);
			}	
		}


		
		public int delete(String statementName) throws DataAccessException {
			// TODO Auto-generated method stub
			return delete(statementName, null);
		}


		
		public Object insert(String statementName) throws DataAccessException {
			// TODO Auto-generated method stub
			return insert(statementName, null);
		}


		
		public List queryForList(final String statementName,final int skipResults,
				final int maxResults) throws DataAccessException {
			// TODO Auto-generated method stub
            return (List)execute(new SqlSessionCallback() {   
                public Object doInSession(SqlSession session) {   
                    return session.selectList(statementName, new RowBounds(skipResults,maxResults));   
                }   
            }); 
		}


		
		public List queryForList(final String statementName, final Object parameterObject,
				final int skipResults, final int maxResults) throws DataAccessException {
			// TODO Auto-generated method stub
            return (List)execute(new SqlSessionCallback() {   
                public Object doInSession(SqlSession session) {   
                    return session.selectList(statementName, parameterObject, new RowBounds(skipResults,maxResults));   
                }   
            }); 
		}


		
		public List queryForList(final String statementName,final Object parameterObject)
				throws DataAccessException {
			// TODO Auto-generated method stub
            return (List)execute(new SqlSessionCallback() {   
                public Object doInSession(SqlSession session) {   
                    return session.selectList(statementName , parameterObject);   
                }   
            });
		}

		
		public List queryForList(final String statementName)
				throws DataAccessException {
			// TODO Auto-generated method stub
            return (List)execute(new SqlSessionCallback() {   
                public Object doInSession(SqlSession session) {   
                    return session.selectList(statementName);   
                }   
            });
		}


		
		public Map queryForMap(String statementName, Object parameterObject,
				String keyProperty, String valueProperty)
				throws DataAccessException {
			// TODO Auto-generated method stub
			return null;
		}


		
		public Map queryForMap(String statementName, Object parameterObject,
				String keyProperty) throws DataAccessException {
			// TODO Auto-generated method stub
			return null;
		}

		/**
		 * empty defined 
		 * @param statementName
		 * @param parameterObject
		 * @param resultObject
		 * @return
		 * @throws DataAccessException
		 */
		public Object queryForObject(String statementName,
				Object parameterObject, Object resultObject)
				throws DataAccessException {
			// TODO Auto-generated method stub
			return null;
		}


		
		public Object queryForObject(final String statementName,
				final Object parameterObject) throws DataAccessException {
			// TODO Auto-generated method stub
			SqlSessionCallback callback = new SqlSessionCallback() {   
                public Object doInSession(SqlSession session) {   
                    return session.selectOne(statementName , parameterObject);   
                }   
            };
			
			return execute(callback);
		}


		
		public Object queryForObject(final String statementName)
				throws DataAccessException {

			SqlSessionCallback callback = new SqlSessionCallback() {   
                public Object doInSession(SqlSession session) {   
                    return session.selectOne(statementName);   
                }   
            };
			
			return execute(callback);
		}


		
		public void update(String statementName, Object parameterObject,
				int requiredRowsAffected) throws DataAccessException {

			int actualRowsAffected = update(statementName, parameterObject);
			if (actualRowsAffected != requiredRowsAffected) {
				throw new JdbcUpdateAffectedIncorrectNumberOfRowsException(
						statementName, requiredRowsAffected, actualRowsAffected);
			}
			
		}

	
		public int update(final String statementName) throws DataAccessException {
			// TODO Auto-generated method stub
            return (Integer)execute(new SqlSessionCallback() {   
                public Object doInSession(SqlSession session) {   
                    return session.update(statementName);   
                }   
            });  
		}

        public int delete(final String statement,final Object parameter) {   
            return (Integer)execute(new SqlSessionCallback() {   
                public Object doInSession(SqlSession session) {   
                    return session.delete(statement, parameter);   
                }   
            });   
        }
        
 
        public int update(final String statement,final Object parameter) {   
            return (Integer)execute(new SqlSessionCallback() {   
                public Object doInSession(SqlSession session) {   
                    return session.update(statement, parameter);   
                }   
            });   
        }   
           
 
    }    
       
    public static interface SqlSessionCallback {   
           
        public Object doInSession(SqlSession session);   
           
    }  	
}
